﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
using ThridLibray;
using Emgu.CV;
using Emgu.CV.Util;
using Emgu.CV.Structure;
using Emgu.CV.CvEnum;
using System.IO;
using FrameDetectionTest.Interface;
using System.Timers;
using Newtonsoft.Json;
using System.Media;

namespace FrameDetectionTest
{
    public delegate void PrintMsgEventHandle(string msg, Color color, float fontSize = 12);
    public delegate void RunEventHandle();
    public delegate void SetTextHandle(string text);
    public partial class Form1 : Form
    {
        #region Static
        private Mat OriginalMat =new Mat();
        private Mat OriginalMat_Old = new Mat();
        private Mat RoiMat = new Mat();
        private Mat RoiLogoMat = new Mat();
        private Mat templateMat = new Mat();

        private Mat modelImage = new Mat();
        private Mat observedImage = new Mat();

        string CurrentProjectFileName = string.Empty;
        string CurrentSerialNumber = string.Empty;
        string CurrentPartNumber = string.Empty;
        string CurrentPalletNumber = string.Empty;
        public string CurrentProjectFilePath = string.Empty;
        Settings settings = null;
        Project CurrentProjectFile = null;
        Point start;
        Point end;
        bool mouseDraw;
        Rectangle PanelRect;
        Rectangle[] EdgeRect = new Rectangle[3];
        Rectangle LogoRect;
        int EdgeFlag = 0;
        bool RoiMode = true;
        bool IsRuning;
        DateTime StartTime;

        CIM cim = new CIM();
        System.Timers.Timer tmrCheckCim;

        System.Timers.Timer timer;
        bool IsTimeOut = false;
        static int MatchSuccessCount;
        long matchTime;
        int matchScore;

        Thread grabThread = null; 
        bool m_bGrabLoop = true;   
        bool m_bStartGrab = false;   
        Mutex m_mutex = new Mutex(); 
        Stopwatch m_grabTime = new Stopwatch();
        private IDevice m_dev;
        private Graphics _g = null;
        private const string SdkFilePath = @".\ImageConvert.dll";
        IntPtr m_pDstRGB = IntPtr.Zero;
        List<IFrameRawData> m_frameList = new List<IFrameRawData>();
        Thread readerThread = null;
        bool m_bShowLoop = true;
        Bitmap m_bitmap = null;
        IFrameRawData m_data;
        int m_framewidth;
        int m_frameheight;
        IMGCNV_SOpenParam m_oParam;
        Rectangle m_bitmapRect;
        Rectangle m_pictureBoxRect;
        BitmapData m_bmpData;
        [DllImport(SdkFilePath, CallingConvention = CallingConvention.StdCall)]
        public static extern int IMGCNV_ConvertToBGR24_Ex(IntPtr pSrcData, ref IMGCNV_SOpenParam pOpenParam, IntPtr pDstData, ref int pDstDataSize, IMGCNV_EBayerDemosaic eBayerDemosaic);
        public enum IMGCNV_EBayerDemosaic
        {
            IMGCNV_DEMOSAIC_NEAREST_NEIGHBOR,        ///< 最近邻 Nearest neighbor
            IMGCNV_DEMOSAIC_BILINEAR,                ///< 双线性 Bilinear
            IMGCNV_DEMOSAIC_EDGE_SENSING,            ///< 边缘检测 Edge sensing
            IMGCNV_DEMOSAIC_NOT_SUPPORT = 255,       ///< 不支持 Not support
        }
        [Serializable]
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 4)]
        public struct IMGCNV_SOpenParam
        {
            public int width;                           ///< 图像宽 Image width
            public int height;                          ///< 图像高 Image Height
            public int paddingX;                        ///< 图像宽填充 Padding X
            public int paddingY;                        ///< 图像高填充 Padding Y
            public int dataSize;                        ///< 图像大小   Image size
            public uint pixelForamt;                    ///< 源图像的图像格式 Image format of source image
        }
        [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory", CharSet = CharSet.Ansi)]
        internal static extern void CopyMemory(IntPtr pDst, IntPtr pSrc, int len);
        #endregion

        public Form1()
        {
            InitializeComponent();
            DeviceListAcq();
            Control.CheckForIllegalCrossThreadCalls = false;
            CvInvoke.UseOpenCL = true;
        }
        #region Event
        private void FrameDetectionTest_Shown(object sender, EventArgs e)
        {
            try
            {
                SetWorkStatus(WorkStatus.Waiting);
                settings = Common.LoadConfig();
                DrawMatches.Print += Print;
                btnClose.Enabled = false;
                btnSoftwareTrigger.Enabled = false;

                if (null == grabThread)
                {
                    grabThread = new Thread(new ThreadStart(GrabThread));
                    grabThread.Start();
                }
                if (null == readerThread)
                {
                    readerThread = new Thread(new ThreadStart(ShowThread));
                    readerThread.Start();
                }
                m_oParam = new IMGCNV_SOpenParam();
                m_bitmapRect = new Rectangle();
                m_bitmapRect.X = 0;
                m_bitmapRect.Y = 0;
                m_pictureBoxRect = new Rectangle(0, 0, pbImage.Width, pbImage.Height);
                m_bmpData = new BitmapData();

                if (settings.IsEnableCIM)
                {
                    TodoServiceCallback.SetSerialNumber += SetText;
                    TodoServiceCallback.runTest += ManualTest;
                    //TodoServiceCallback.runTest += test_release;
                    TodoServiceCallback.Print += Print;
                    TodoServiceCallback.EQPID += settings.EquipmentId;

                    cim.printmessage += Print;
                    cim.EQPID = settings.EquipmentId;

                    ConnectCIM();
                    EnableCheckCim(5000);
                    cim.OnLine();
                    SetWorkStatus(WorkStatus.Preparing);
                }
                else
                {
                    SetWorkStatus(WorkStatus.Offline);
                }
                if(comboBox_DevList.Text != String.Empty)
                {
                    BnOpen_Click(sender, new EventArgs());
                }
            }
            catch (Exception ex)
            {
                Print(ex.Message, Color.Red);
                SetWorkStatus(WorkStatus.Offline);
            }

        }
        private void cbDeviceList_SelectedIndexChanged(object sender, EventArgs e)
        {
            //DeviceListAcq();
        }
        private void 导入工程ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            //Mat ShowMat = new Mat();
            string FilePath = LoadPrj();
            if (FilePath == null) return;
            OriginalMat = new Mat(FilePath);
            CvInvoke.Resize(OriginalMat, OriginalMat, new Size(912, 608));
            pbImage.Image = OriginalMat;
        }
        private void OriginalPic_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Location.X > 912 || e.Location.Y > 608)
            {
                return;
            }
            start = e.Location;
            mouseDraw = true;//开始绘制
            if (!RoiMode)
            {
                //switch (EdgeFlag)
                //{
                //    case 0://上边缘区域
                //        groupBox5.Text = "正在划定上边缘区域";
                //        break;
                //    case 1://左边缘区域
                //        groupBox5.Text = "正在划定左边缘区域";
                //        break;
                //    case 2://右边缘区域
                //        groupBox5.Text = "正在划定右边缘区域";
                //        break;
                //}
            }
        }
        private void OriginalPic_MouseMove(object sender, MouseEventArgs e)
        {
            if (RoiMode && mouseDraw)
            {
                if (e.Button != MouseButtons.Left)
                {
                    mouseDraw = false;
                    return;
                }
                end = e.Location;
                PanelRect.Location = new Point(Math.Min(start.X, end.X),Math.Min(start.Y, end.Y));
                PanelRect.Size = new Size(Math.Abs(start.X - end.X),Math.Abs(start.Y - end.Y));
                pbImage.Invalidate();
            }
            else if(!RoiMode && mouseDraw)
            {
                if (e.Button != MouseButtons.Left)
                {
                    mouseDraw = false;
                    return;
                }
                end = e.Location;
                LogoRect.Location = new Point(Math.Min(start.X, end.X), Math.Min(start.Y, end.Y));
                LogoRect.Size = new Size(Math.Abs(start.X - end.X), Math.Abs(start.Y - end.Y));
                pbImage.Invalidate();
            }
        }
        private void OriginalPic_MouseUp(object sender, MouseEventArgs e)
        {
            if(pbImage.Image == null)
            {
                return;
            }
            if (e.Location.X > 912 || e.Location.Y > 608)
            {
                return;
            }
            if (RoiMode && mouseDraw && PanelRect.Width > 0 && PanelRect.Height > 0)
            {
                mouseDraw = false;
                Print("Panel 破片测试区域载入完成:请确认测试区域完全内嵌在产品边框内部", Color.Green);
            }
            else if (!RoiMode && mouseDraw && LogoRect.Width > 0 && LogoRect.Height > 0)
            {
                mouseDraw = false;
                Print("Logo 测试区域载入完成:请确认测试区域", Color.Green);
            }
        }
        private void OriginalPic_Paint(object sender, PaintEventArgs e)
        {
            if (RoiMode && mouseDraw)
            {
                if (pbImage.Image != null)
                {
                    if (PanelRect != null && PanelRect.Width > 0 && PanelRect.Height > 0)
                    {
                        e.Graphics.DrawString("镜面测试区域",new Font("微软雅黑", 10), new SolidBrush(Color.Green),new Point(PanelRect.X, PanelRect.Y-22));
                        e.Graphics.DrawRectangle(new Pen(Color.Green, 2), PanelRect);
                    }
                }
            }else if (!RoiMode && mouseDraw)
            {
                if (pbImage.Image != null)
                {
                    if (PanelRect != null && LogoRect.Width > 0 && LogoRect.Height > 0)
                    {
                        e.Graphics.DrawString("Logo测试区域", new Font("微软雅黑", 10), new SolidBrush(Color.WhiteSmoke), new Point(LogoRect.X, LogoRect.Y - 22));
                        e.Graphics.DrawRectangle(new Pen(Color.WhiteSmoke, 2), LogoRect);
                    }
                }
            }
        }
        private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Config config = new Config(settings);
            config.ShowDialog();

        }
        private void BnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                m_dev = Enumerator.GetDeviceByIndex(comboBox_DevList.SelectedIndex);
                if(m_dev == null)
                {
                    Print("未成功连接相机，请检查相机连接",Color.Red);
                    return;
                }
                m_dev.CameraOpened += OnCameraOpen;
                m_dev.ConnectionLost += OnConnectLoss;
                m_dev.CameraClosed += OnCameraClose;
                if (!m_dev.Open())
                {
                    Print("Open camera failed",Color.Red);
                    return;
                }
                SetCtrlWhenOpen();
                m_dev.TriggerSet.Open(TriggerSourceEnum.Software);
                using (IEnumParameter p = m_dev.ParameterCollection[ParametrizeNameSet.ImagePixelFormat])
                {
                    p.SetValue("Mono8");
                }
                using (IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.ExposureTime])
                {
                    p.SetValue(20000);
                    tbExposure.Text = p.GetValue().ToString();
                }
                using (IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.GainRaw])
                {
                    p.SetValue(2.0);
                    tbGain.Text = p.GetValue().ToString();
                }

                using (IBooleanParameter p = m_dev.ParameterCollection[ParametrizeNameSet.AcquisitionFrameRateEnable])
                {
                    if (false == p.SetValue(false))
                    {
                        Print("set FrameRateEnable failed",Color.Red);
                    }
                }
                using (IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.AcquisitionFrameRate])
                {
                    p.SetValue(10);
                    tbFrame.Text = p.GetValue().ToString();
                }

                using(IEnumParameter p = m_dev.ParameterCollection[ParametrizeNameSet.BalanceWhiteAuto])
                {
                    if(false == p.SetValue("Continuous"))
                    {
                        Print("Set BalanceWhiteAuto Continuous Failed", Color.Red);
                    }
                }
                m_dev.StreamGrabber.SetBufferCount(2);
                if (!m_dev.StreamGrabber.Start(GrabStrategyEnum.grabStrartegySequential, GrabLoop.ProvidedByUser))
                {
                    MessageBox.Show(@"Start grabbing failed");
                    return;
                }

                m_bStartGrab = true;
                
            }
            catch (Exception ex)
            {
                Print(ex.Message,Color.Red);
            }
        }
        private void OnCameraOpen(object sender, EventArgs e)
        {
            this.Invoke(new Action(() =>
            {
                btnOpen.Enabled = false;
                btnSoftwareTrigger.Enabled = true;
                btnClose.Enabled = true;
                SetStatePic(1);
            }));
        }
        private void OnCameraClose(object sender, EventArgs e)
        {
            if (m_frameList.Count > 0)
            {
                m_mutex.WaitOne();
                m_frameList.Clear();
                m_mutex.ReleaseMutex();
            }
            if (m_bitmap != null)
            {
                m_bitmap.Dispose();
            }

            this.Invoke(new Action(() =>
            {
                btnOpen.Enabled = true;
                btnSoftwareTrigger.Enabled = false;
                btnClose.Enabled = false;
                SetStatePic(0);
            }));
        }
        private void OnConnectLoss(object sender, EventArgs e)
        {
            m_bStartGrab = false;
            readerThread.Join(100);
            if (m_frameList.Count > 0)
            {
                m_mutex.WaitOne();
                m_frameList.Clear();
                m_mutex.ReleaseMutex();
            }
            Marshal.FreeHGlobal(m_pDstRGB);
            if (m_data != null)
            {
                m_data.Dispose();
            }
            if (m_bitmap != null)
            {
                m_bitmap.Dispose();
            }
            m_dev.ShutdownGrab();
            m_dev.Dispose();
            m_dev = null;

            this.Invoke(new Action(() =>
            {
                btnOpen.Enabled = true;
                btnSoftwareTrigger.Enabled = false;
                btnClose.Enabled = false;
                SetStatePic(0);
            }));
        }
        private void BnEnum_Click(object sender, EventArgs e)
        {
            DeviceListAcq();
        }
        private void BnClose_Click(object sender, EventArgs e)
        {
            m_bStartGrab = false;
            if (m_bShowLoop)
            {
                readerThread.Join(100);
            }

            //清除数据
            if (m_frameList.Count > 0)
            {
                m_mutex.WaitOne();
                m_frameList.Clear();
                m_mutex.ReleaseMutex();
            }
            Marshal.FreeHGlobal(m_pDstRGB);
            if (m_data != null)
            {
                m_data.Dispose();
            }
            if (m_bitmap != null)
            {
                m_bitmap.Dispose();
            }
            m_framewidth = 0;
            m_frameheight = 0;
            try
            {
                if (m_dev == null)
                {
                    throw new InvalidOperationException("Device is invalid");
                }
                m_dev.ShutdownGrab();
                m_dev.Close();                             
            }
            catch (Exception exception)
            {
                Catcher.Show(exception);
            }
            SetCtrlWhenClose();
        }
        private void BnGetParam_Click(object sender, EventArgs e)
        {
            using(IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.AcquisitionFrameRate])
            {
                tbFrame.Text = p.GetValue().ToString();
            }
            using(IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.ExposureTime])
            {
                tbExposure.Text = p.GetValue().ToString();
            }
        }
        private void BnSetParam_Click(object sender, EventArgs e)
        {
            try
            {
                float fValue = float.Parse(tbExposure.Text);
                using (IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.ExposureTime])
                {
                    p.SetValue(fValue);
                }
                float gValue = float.Parse(tbGain.Text);
                using (IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.GainRaw])
                {
                    p.SetValue(gValue);
                }

                float frameValue = float.Parse(tbFrame.Text);
                using (IFloatParameter p = m_dev.ParameterCollection[ParametrizeNameSet.AcquisitionFrameRate])
                {
                    if (false == p.SetValue(frameValue))
                    {
                        Print("set FrameRate failed", Color.Red);
                    }
                }
            }
            catch
            {
                return;
            }
        }
        private void BnTriggerExec_Click(object sender, EventArgs e)
        {
            if (m_dev == null)
            {
                throw new InvalidOperationException("Device is invalid");
            }
            try
            {
                m_grabTime.Reset();
                m_grabTime.Start(); 
                m_dev.ExecuteSoftwareTrigger();
            }
            catch (Exception exception)
            {
                Catcher.Show(exception);
            }
        }
        private void SavePrjButton_Click(object sender, EventArgs e)
        {
            string PrjName = string.Empty;
            if(OriginalMat.IsEmpty)
            {
                Print("请先拍摄待测产品、划定测试区域后保存工程",Color.Red);
                return;
            }
            if(PanelRect.Width == 0 || PanelRect.Height == 0)
            {
                Print("未划定测试区域，无法保存工程",Color.Red);
                return;
            }
            Mat SaveMat = new Mat();
            OriginalMat.CopyTo(SaveMat);
            if (CurrentProjectFile == null)
            {
                if(MessageBox.Show("当前未选定工程文件，自动创建新的工程文件","FrameDetection",MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    CreatePrj createPrj = new CreatePrj();
                    createPrj.ShowDialog();
                    if (createPrj.DialogResult != DialogResult.OK)
                    {
                        return;
                    }
                    else
                    {
                        PrjName = createPrj.ProjectFileName;
                    }
                }
                else
                {
                    return;
                }
                CurrentProjectFile = new Project
                {
                    Roi_Panel_X = 0,
                    Roi_Panel_Y = 0,
                    Roi_Logo_X = 0,
                    Roi_Logo_Y = 0,
                    Logo_enable = false,
                };
            }
            else
            {
                PrjName = CurrentProjectFileName;
            }
            if (PanelRect.Width == 0 || PanelRect.Height == 0)
            {
                Print("未划定主测试区域，无法保存", Color.Red);
                return;
            }
            else
            {
                CurrentProjectFile.Roi_Panel_X = PanelRect.X;
                CurrentProjectFile.Roi_Panel_Y = PanelRect.Y;
                CurrentProjectFile.Roi_Panel_Width = PanelRect.Width;
                CurrentProjectFile.Roi_Panel_Height = PanelRect.Height;
                CvInvoke.Rectangle(SaveMat, PanelRect, new MCvScalar(255, 0, 0));
                CvInvoke.PutText(SaveMat, String.Format("PanelTest Area"), new Point(PanelRect.X - 5, PanelRect.Y - 5), FontFace.HersheySimplex, 1, new MCvScalar(255, 255, 255));
            }
            if(LogoRect.Width != 0 && LogoRect.Height != 0)
            {
                CurrentProjectFile.Logo_enable = true;
                CurrentProjectFile.Roi_Logo_X = LogoRect.X;
                CurrentProjectFile.Roi_Logo_Y = LogoRect.Y;
                CurrentProjectFile.Roi_Logo_Width = LogoRect.Width;
                CurrentProjectFile.Roi_Logo_Height = LogoRect.Height;
                CvInvoke.Rectangle(SaveMat, LogoRect, new MCvScalar(255, 0, 0));
                CvInvoke.PutText(SaveMat, String.Format("LogoTest Area"), new Point(LogoRect.X - 5, LogoRect.Y - 5), FontFace.HersheySimplex, 1, new MCvScalar(255, 255, 255));
            }
            string PrjSavePath = settings.ProjectPath  + "prj\\" + PrjName + ".json";
            if (!Directory.Exists(settings.ProjectPath + "prj\\"))
            {
                Directory.CreateDirectory(settings.ProjectPath + "prj\\");
            }
            Common.SaveProject(CurrentProjectFile, PrjSavePath);//保存json工程文件
            if(!Directory.Exists(settings.ProjectPath + "pic\\"))
            {
                Directory.CreateDirectory(settings.ProjectPath + "pic\\");
            }
            if (!PrjName.Contains('='))
            {
                //Base机种则需要保存图片，如果不为base机种，则不需要保存图片
                SaveMat.Save(settings.ProjectPath + "pic\\" + PrjName.Trim() + ".bmp");
            }
            if(!File.Exists(settings.ProjectPath + "list.lst"))
            {
                FileStream fs = File.Create(settings.ProjectPath + "list.lst");
                fs.Dispose();
            }
            Common.AddList(settings.ProjectPath + "list.lst", PrjName);
            CurrentProjectFile = null;
            PanelRect = new Rectangle();
            EdgeRect[0] = new Rectangle();
            EdgeRect[1] = new Rectangle();
            EdgeRect[2] = new Rectangle();
        }
        private void TestButton_Click(object sender, EventArgs e)
        {
            Stopwatch sw = Stopwatch.StartNew();
            Test();
            RoiLogoMat = Roi(OriginalMat_Old, new Rectangle(LogoRect.X * 6, LogoRect.Y * 6, LogoRect.Width * 6, LogoRect.Height * 6));
            LogoTest();
            sw.Stop();
            Print($"总花费时间{sw.ElapsedMilliseconds} ms", Color.Green);
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (m_dev != null)
            {
                m_dev.Dispose();
                m_dev = null;

            }
            grabThread.Abort();
            readerThread.Abort();
            base.OnClosed(e);
        }
        private void 版本管理ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Interface.Version version = new Interface.Version();
            version.ShowDialog();
        }
        private void 加载ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (!string.IsNullOrEmpty(settings.ProjectPath))
                {
                    if (Directory.Exists(settings.ProjectPath))
                    {
                        Project OldProjectFile = new Project();
                        string OldProjectFileName = string.Empty;
                        string OldPartNumber = string.Empty;

                        OldProjectFile = CurrentProjectFile;
                        OldProjectFileName = CurrentProjectFileName;
                        OldPartNumber = CurrentPartNumber;

                        LoadProject loadProject = new LoadProject(settings.ListPath,settings.ProjectPath);
                        DialogResult = loadProject.ShowDialog();
                        if (DialogResult == DialogResult.OK)
                        {
                            CurrentProjectFilePath = loadProject.CurrentProjectFilePath;
                            CurrentProjectFile = Common.LoadProject(loadProject.CurrentProjectFilePath);
                            CurrentProjectFileName = loadProject.CurrentProjectFileName;
                            groupBox2.Text = CurrentProjectFileName;
                            SetWorkStatus(WorkStatus.Ready);
                            Print("Panel破片测试参数: 起始点X:  " + CurrentProjectFile.Roi_Panel_X + "     起始点Y:  " + CurrentProjectFile.Roi_Panel_Y, Color.Green);
                            Print("Panel破片测试参数: 宽:  " + CurrentProjectFile.Roi_Panel_Width + "     高:  " + CurrentProjectFile.Roi_Panel_Height, Color.Green);
                            PanelRect = new Rectangle(CurrentProjectFile.Roi_Panel_X, CurrentProjectFile.Roi_Panel_Y, CurrentProjectFile.Roi_Panel_Width, CurrentProjectFile.Roi_Panel_Height);
                            if (CurrentProjectFile.Logo_enable)
                            {
                                Print("Logo测试参数: 起始点X:  " + CurrentProjectFile.Roi_Logo_X + "     起始点Y:  " + CurrentProjectFile.Roi_Logo_Y, Color.Green);
                                Print("Logo测试参数: 宽:  " + CurrentProjectFile.Roi_Logo_Width + "     高:  " + CurrentProjectFile.Roi_Logo_Height, Color.Green);
                                LogoRect = new Rectangle(CurrentProjectFile.Roi_Logo_X, CurrentProjectFile.Roi_Logo_Y, CurrentProjectFile.Roi_Logo_Width, CurrentProjectFile.Roi_Logo_Height);
                            }
                        }
                        else
                        {
                            CurrentProjectFile = OldProjectFile;
                            CurrentProjectFileName = OldProjectFileName;
                            CurrentPartNumber = OldPartNumber;
                        }
                    }
                    else
                    {
                        Print("工程文件路径不存在，请检查软件路径设置", Color.Red);
                    }
                }
                else
                {
                    Print("请检查软件路径设置", Color.Red);
                }
            }
            catch
            {
                Print("加载工程文件失败", Color.Red);
            }
        }
        private void 切换窗口模式ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.FormBorderStyle == FormBorderStyle.Sizable)
            {
                this.FormBorderStyle = FormBorderStyle.None;
            }
            else
            {
                this.FormBorderStyle = FormBorderStyle.Sizable;
            }
        }
        private void 相机界面控制ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            groupBox6.Visible = !groupBox6.Visible;
        }
        private void 区域模式选择ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (RoiMode)
            {
                RoiMode = !RoiMode;
                groupBox5.Text = "正在划定Logo测试区域...";
            }
            else
            {
                RoiMode = !RoiMode;
                groupBox5.Text = "正在划定主测试区域...";
            }
        }
        private void 载入Logo模板ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string FilePath = LoadPrj();
            if (FilePath == null) return;
            templateMat = new Mat(FilePath);
            TemplatePic.Image = templateMat;
        }
        #endregion

        #region Function
        public bool Test()
        {
            bool result = true;
            try
            {
                if (settings.IsCameraEnable)
                {
                    GetFrame();
                }
                Thread.Sleep(settings.GetFrameDataIntervalTime);
                if (OriginalMat.IsEmpty)
                {
                    throw new Exception("未成功载入测试图片");
                }
                RoiMat = Roi(OriginalMat,PanelRect); //912, 608
                if (settings.IsCameraEnable)
                {
                    Mat LogoMat = new Mat();
                    Rectangle logoRect_old = new Rectangle(LogoRect.X * 6, LogoRect.Y * 6, LogoRect.Width * 6, LogoRect.Height * 6);
                    LogoMat = Roi(OriginalMat_Old, logoRect_old);
                    LogoPic.Image = LogoMat;
                }
                pbImage.Image = OriginalMat;
                if (pbImage.Image != null && !PanelRect.IsEmpty)
                {
                    if (PanelRect.Width > 0 && PanelRect.Height > 0)
                    {
                        Graphics a = this.pbImage.CreateGraphics();
                        a.DrawRectangle(new Pen(Color.Green, 2), PanelRect);
                        a.DrawString("镜面测试区域", new Font("微软雅黑", 10), new SolidBrush(Color.Green), new Point(PanelRect.X, PanelRect.Y - 22));
                        a.DrawRectangle(new Pen(Color.WhiteSmoke, 2), LogoRect);
                        a.DrawString("Logo测试区域", new Font("微软雅黑", 10), new SolidBrush(Color.WhiteSmoke), new Point(LogoRect.X, LogoRect.Y - 22));
                    }
                }
                else
                {
                    throw new Exception("未找到或加载测试区域");
                }
                MntColor[] mntcolor1;
                mntcolor1 = TestMode1();
                if(mntcolor1[0] != MntColor.Black)
                {
                    if (ConsisitencyTest(mntcolor1))
                    {
                        Print("Corner Test Pass...Border Testing...", Color.Green);
                        MntColor[] MntUpBorderColor;
                        MntColor[] MntDownBorderColor;
                        MntUpBorderColor = TestUpBorder();
                        MntDownBorderColor = TestDownBorder();
                        if (ConsisitencyTest(MntUpBorderColor))
                        {
                            Print("Up Border Test Pass...Down Border Testing...", Color.Green);
                            if (ConsisitencyTest(MntDownBorderColor))
                            {
                                Print("Down Border Test Pass...Height Border Testing...", Color.Green);
                                MntColor[] MntLeftBorderColor;
                                MntColor[] MntRightBorderColor;
                                MntLeftBorderColor = TestLeftBorder();
                                MntRightBorderColor = TestRightBorder();
                                if (ConsisitencyTest(MntLeftBorderColor))
                                {
                                    Print("Left Border Test Pass...Right Border Testing...", Color.Green);
                                    if (ConsisitencyTest(MntRightBorderColor))
                                    {
                                        Print("All Test Pass...", Color.Green);
                                        SetWorkStatus(WorkStatus.Pass);
                                        result = true;
                                        if (settings.BrightLineEnable)
                                        {
                                            MntColor[] MntBrightLineColor;
                                            MntBrightLineColor = TestBrightLine();
                                            if (!ConsisitencyTest(MntBrightLineColor))
                                            {
                                                SoundPlayer sound = new SoundPlayer(AppDomain.CurrentDomain.BaseDirectory + "res\\BrightLine.wav");
                                                sound.Play();
                                                sound.Dispose();
                                            }
                                        }
                                        return true;
                                    }
                                    else
                                    {
                                        throw new Exception("Right Border Test Failed");
                                    }
                                }
                                else
                                {
                                    throw new Exception("Left Border Test Failed");
                                }
                            }
                            else
                            {
                                throw new Exception("Down Border Test Failed");
                            }
                        }
                        else
                        {
                            throw new Exception("Up Border Test Failed");
                        }
                    }
                    else
                    {
                        throw new Exception("Corner Test Failed");
                    }
                }
                else
                {
                    return false;
                }

            }catch (Exception ex)
            {

                Print(ex.Message,Color.Red);
                SetWorkStatus(WorkStatus.NG);
                result = false;
                return false;
            }
        }
        public void ManualTest()
        {
            if (IsRuning)
            {
                return;
            }
            SetWorkStatus(WorkStatus.Waiting);
            Print("", Color.White);
            ClearSerialNumberText();
            bool testResult1 = false;
            bool testResult2 = true;
            try
            {
                if (CurrentProjectFile == null)
                {
                    throw new Exception("未加载机种文件，请手动选择机种文件或者滑动测试区域后保存");
                    //ClearSerialNumberText();
                }
                StartTime = DateTime.Now;//开始计时
                string SN = string.Empty;
                Print(string.Format("{0} 开始测试", TodoServiceCallback.current_cim_to_station.Sn), Color.Green);
                testResult1 = Test();
                Common.msDelay(500);
                if (!testResult1)
                {
                    Print("测试失败，正在进行重测",Color.Red);
                    for(int i = 0; i < settings.RetestTime; i++)
                    {
                        string message = "第" + (i + 1) + "次复判中...";
                        Print(message, Color.Red);
                        testResult2 = Test();
                        Common.msDelay(200);
                        if (testResult2) goto label1;
                    }
                    SetWorkStatus(WorkStatus.NG);
                    string ngFilePath = Path.GetPathRoot(AppDomain.CurrentDomain.BaseDirectory) + "FrameDetectionTestLog" + "\\Cv\\NG\\" + DateTime.Now.ToString("yyyyMMdd") + "\\";
                    if (!Directory.Exists(ngFilePath))
                    {
                        Directory.CreateDirectory(ngFilePath);
                    }
                    OriginalMat.Save(ngFilePath + DateTime.Now.ToString("HHmmss") + ".jpg");
                    throw new Exception("测试失败,为不良品");
                }
                label1:
                SetWorkStatus(WorkStatus.Pass);//PASS
                string filepath = Path.GetPathRoot(AppDomain.CurrentDomain.BaseDirectory) + "FrameDetectionTestLog" + "\\Cv\\OK\\" + DateTime.Now.ToString("yyyyMMdd") + "\\";
                if (!Directory.Exists(filepath))
                {
                    Directory.CreateDirectory(filepath);
                }
                if (settings.IsEnableCIM)
                {
                    OriginalMat.Save(filepath + TodoServiceCallback.current_cim_to_station.Sn.ToString() + "-" + DateTime.Now.ToString("HHmmss") + ".jpg");
                }
                else
                {
                    OriginalMat.Save(filepath + DateTime.Now.ToString("HHmmss") + ".jpg");
                }
                SoundPlayer sound = new SoundPlayer(AppDomain.CurrentDomain.BaseDirectory + "res\\OK.wav");
                sound.Play();
                sound.Dispose();
                try
                {
                    CIM.EQPCALLCIMDATA eqp_call_cim_data = new CIM.EQPCALLCIMDATA
                    {
                        TagName = TodoServiceCallback.current_cim_to_station.TagName,
                        RequestNo = TodoServiceCallback.current_cim_to_station.RequestNo,
                        EqpSeq = TodoServiceCallback.current_cim_to_station.EqpSeq,
                        Sn = TodoServiceCallback.current_cim_to_station.Sn,
                        ResultFlag = "1",    // 1:Ok   2:Fail  3:Retry
                        NameFlag = TodoServiceCallback.current_cim_to_station.NameFlag,
                        Eqpid = settings.EquipmentId,
                        TestSlot = "1",
                        ErrorCode = "Logo",
                        TestTime = ((DateTime.Now - StartTime).TotalMilliseconds / 1000.0).ToString("0.0"),//测试时间
                        ProductSN = "SN",
                    };
                    cim.ReportToCIM(eqp_call_cim_data);
                }
                catch
                {
                    Print("Report to CIM failed", Color.Red);
                }
            }
            catch (Exception ex)
            {
                SoundPlayer sound = new SoundPlayer(AppDomain.CurrentDomain.BaseDirectory + "res\\NG.wav");
                sound.Play();
                sound.Dispose();
                Print(ex.Message, Color.Red);
                try
                {
                    CIM.EQPCALLCIMDATA eqp_call_cim_data = new CIM.EQPCALLCIMDATA
                    {
                        TagName = TodoServiceCallback.current_cim_to_station.TagName,
                        RequestNo = TodoServiceCallback.current_cim_to_station.RequestNo,
                        EqpSeq = TodoServiceCallback.current_cim_to_station.EqpSeq,
                        Sn = TodoServiceCallback.current_cim_to_station.Sn,
                        ResultFlag = "3",    // 1:Ok   2:Fail  3:Retry
                        NameFlag = TodoServiceCallback.current_cim_to_station.NameFlag,
                        Eqpid = settings.EquipmentId,
                        TestSlot = "1",
                        ErrorCode = "Logo",
                        TestTime = ((DateTime.Now - StartTime).TotalMilliseconds / 1000.0).ToString("0.0"),//测试时间
                        ProductSN = "SN",
                    };
                    cim.ReportToCIM(eqp_call_cim_data);
                }catch
                {
                    Print("Report to CIM failed", Color.Red); 
                }
            }
            finally
            {
                try
                {
                    Log.CsvPrint(TodoServiceCallback.current_cim_to_station.Sn, testResult2);
                    CurrentPalletNumber = string.Empty;
                    TodoServiceCallback.current_cim_to_station = null;
                    TodoServiceCallback.IsWork = false;
                }
                catch (Exception ex)
                {
                    Print(ex.Message, Color.Red);
                }
                string TestTime = ((DateTime.Now - StartTime).TotalMilliseconds / 1000.0).ToString("0.0");
                Print("本次测试时间为" + TestTime, Color.Gray);
            }
        }
        private void ClearSerialNumberText()
        {
            Invoke(new Action(() =>
            {
                SnTextBox.Focus();
                SnTextBox.Clear();
            }));
        }
        private void GetFrame()
        {
            if (m_dev == null)
            {
                throw new InvalidOperationException("Device is invalid");
            }
            try
            {
                m_grabTime.Reset();
                m_grabTime.Start();
                m_dev.ExecuteSoftwareTrigger();
            }
            catch (Exception exception)
            {
                Catcher.Show(exception);
            }
        }
        private void ConnectCIM()
        {
            //Task.Run(() =>
            //{
            //    cim.ConnectCIMServer();
            //    SetCimStatus();
            //});
            cim.ConnectCIMServer();
            SetCimStatus();

        }
        private void SetCimStatus()
        {
            if (cim.IsConnect)
            {
                string msg = string.Format("已连接CIM系统  设备ID:{0}", settings.EquipmentId);
                Print(msg, Color.Green);
            }
            else
            {
                throw new Exception("连接CIM失败");
            }
        }
        private void EnableCheckCim(int IntervalTimes)
        {
            tmrCheckCim = new System.Timers.Timer(IntervalTimes);
            tmrCheckCim.Elapsed += TmrCheckCim_Elapsed;
            tmrCheckCim.Enabled = true;
        }
        private void TmrCheckCim_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                cim.CheckChannel();
            }
            catch (Exception ex)
            {
                //throw new Exception(string.Format("Report to cim failed: {0}", ex.Message));
                Log.Print(ex.Message, Log.LogType.workmessage);
            }
        }
        private void SetCtrlWhenOpen()
        {
            btnOpen.Enabled = false;
            btnClose.Enabled = true;
            btnSoftwareTrigger.Enabled = true;
            tbExposure.Enabled = true;
            tbGain.Enabled = true;
            bnGetParam.Enabled = true;
            bnSetParam.Enabled = true;
            tbFrame.Enabled = true;
        }
        private void SetCtrlWhenClose()
        {
            btnOpen.Enabled = true;
            btnClose.Enabled = false;
            //bnStartGrab.Enabled = false;
            //bnStopGrab.Enabled = false;
            //bnContinuesMode.Enabled = false;
            //bnTriggerMode.Enabled = false;
            //cbSoftTrigger.Enabled = false;
            btnSoftwareTrigger.Enabled = false;
            tbExposure.Enabled = false;
            tbGain.Enabled = false;
            bnGetParam.Enabled = false;
            bnSetParam.Enabled = false;
        }
        private string LoadPrj()
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Multiselect = false;
            dialog.Title = "请选择工程";
            dialog.Filter = "图片文件(*.jpg,*.png,*.bmp)|*.jpg;*.png;*.bmp";
            dialog.InitialDirectory = @"E:\破片\不良品样本";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                return dialog.FileName;
            }
            return null;
        }
        public void Print(string msg, Color color, Single FontSize = 12)
        {
            if (InvokeRequired)
            {
                Invoke(new Action(() => { Print(msg, color, FontSize); }));
            }
            else
            {
                WorkMessage.SelectionColor = color;
                WorkMessage.SelectionFont = new Font(WorkMessage.SelectionFont.Name, FontSize, WorkMessage.SelectionFont.Style);
                switch (msg)
                {
                    case "":
                        WorkMessage.Clear();
                        break;
                    case "\n":
                        WorkMessage.AppendText("\n");
                        WorkMessage.SelectionStart = WorkMessage.Text.Length;
                        WorkMessage.ScrollToCaret();
                        break;
                    case "F":
                        WorkMessage.SelectionStart = 0;
                        WorkMessage.ScrollToCaret();
                        break;
                    default:
                        string message = string.Format("[{0}] {1}", DateTime.Now.ToString("yyy-MM-dd HH:mm:ss"), msg.Trim());
                        WorkMessage.AppendText(message + '\n');
                        WorkMessage.SelectionStart = WorkMessage.Text.Length;
                        WorkMessage.ScrollToCaret();
                        break;
                }
            }
        }
        private Mat Roi(Mat inputMat,Rectangle rect)
        {
            try
            {
                // start.X, start.Y, end.X - start.X, end.Y - start.Y
                Mat outputMat = new Mat(inputMat, new Rectangle(rect.X,rect.Y,rect.Width,rect.Height));
                return outputMat;
            }
            catch
            {
                Print("请检查相机连接，并正向滑动有效检测区域", Color.Red);
            }
            return null;
        }
        private void SetStatePic(int state)
        {
            if (state == 0)
            {
                CameraStatusLabel.Image = FrameDetectionTest.Properties.Resources.wrong;
            }
            else
            {
                CameraStatusLabel.Image = FrameDetectionTest.Properties.Resources.right;
            }
        }
        private void DeviceListAcq()
        {
            // 设备搜索 
            // device search 
            comboBox_DevList.Items.Clear();
            List<IDeviceInfo> li = Enumerator.EnumerateDevices();
            if (li.Count > 0)
            {
                for (int i = 0; i < li.Count; i++)
                {
                    comboBox_DevList.Items.Add(li[i].Key);
                }
                comboBox_DevList.Text = li[0].Key;
                btnOpen.Enabled = true;
            }
        }
        private MntColor[] TestMode1()
        {
            Mat RoiExtractColorMat = new Mat();
            RoiMat.CopyTo(RoiExtractColorMat);
            Point MiddlePoint = new Point((int)RoiExtractColorMat.Width / 2,(int)RoiExtractColorMat.Height /2);

            //可以精细化判断
            Rectangle AreaMiddle = new Rectangle(new Point(MiddlePoint.X-5,MiddlePoint.Y-5),new Size(10,10));
            Rectangle AreaLeftUp = new Rectangle(new Point(20,20),new Size(10,10));
            Rectangle AreaRightUp = new Rectangle(new Point(RoiExtractColorMat.Width - 30, 20), new Size(10, 10));
            Rectangle AreaRightDown = new Rectangle(new Point(RoiExtractColorMat.Width - 30, RoiExtractColorMat.Height - 30), new Size(10, 10));
            Rectangle AreaLeftDown = new Rectangle(new Point(20 , RoiExtractColorMat.Height - 30), new Size(10, 10));

            ExtractColorPic.Image = RoiExtractColorMat;

            MntColor[] Mode1Result = new MntColor[5];
            Mode1Result[0] = RangeColorRecognize(RoiExtractColorMat, AreaMiddle);
            Mode1Result[1] = RangeColorRecognize(RoiExtractColorMat, AreaLeftUp);
            Mode1Result[2] = RangeColorRecognize(RoiExtractColorMat, AreaRightUp);
            Mode1Result[3] = RangeColorRecognize(RoiExtractColorMat, AreaRightDown);
            Mode1Result[4] = RangeColorRecognize(RoiExtractColorMat, AreaLeftDown);

            CvInvoke.Rectangle(RoiExtractColorMat,AreaMiddle,new MCvScalar(255,0,0));
            CvInvoke.Rectangle(RoiExtractColorMat, AreaLeftUp, new MCvScalar(255, 0, 0));
            CvInvoke.Rectangle(RoiExtractColorMat, AreaRightUp, new MCvScalar(255, 0, 0));
            CvInvoke.Rectangle(RoiExtractColorMat, AreaRightDown, new MCvScalar(255, 0, 0));
            CvInvoke.Rectangle(RoiExtractColorMat, AreaLeftDown, new MCvScalar(255, 0, 0));

            ExtractColorPic.Image = RoiExtractColorMat;
            return Mode1Result;
        }
        private MntColor[] TestUpBorder()
        {
            Mat RoiExtractColorMat = new Mat();
            RoiMat.CopyTo(RoiExtractColorMat);    
            Point MiddlePoint = new Point((int)RoiExtractColorMat.Width / 2, (int)RoiExtractColorMat.Height / 2);
            Rectangle AreaMiddle = new Rectangle(new Point(MiddlePoint.X - 5, MiddlePoint.Y - 5), new Size(10, 10));

            int WidthAreaNum = (int)Math.Floor((decimal)RoiExtractColorMat.Width / 20) - 4;
            Rectangle[] UpBorderArea = new Rectangle[WidthAreaNum + 1];
            for (int i = 1; i <= WidthAreaNum; i++)
            {
                UpBorderArea[i] = new Rectangle((i + 2) * 20, 20, 10, 10);
            }

            MntColor[] UpAreaResult = new MntColor[WidthAreaNum + 1];

            UpAreaResult[0] = RangeColorRecognize(RoiExtractColorMat, AreaMiddle);
            for (int i = 1; i <= WidthAreaNum; i++)
            {
                UpAreaResult[i] = RangeColorRecognize(RoiExtractColorMat, UpBorderArea[i]);
            }
            Mat ShowMat = new Mat();
            RoiMat.CopyTo(ShowMat); 
            CvInvoke.Rectangle(ShowMat, AreaMiddle, new MCvScalar(255, 0, 0));
            for (int i = 0; i <= WidthAreaNum; i++)
            {
                CvInvoke.Rectangle(ShowMat, UpBorderArea[i], new MCvScalar(255, 0, 0));
            }
            ExtractColorPic.Image = ShowMat;
            //增加上边缘补充测试

            return UpAreaResult;
        }
        private MntColor[] TestDownBorder()
        {
            Mat RoiExtractColorMat = new Mat();
            RoiMat.CopyTo(RoiExtractColorMat); 
            Point MiddlePoint = new Point((int)RoiExtractColorMat.Width / 2, (int)RoiExtractColorMat.Height / 2);
            Rectangle AreaMiddle = new Rectangle(new Point(MiddlePoint.X - 5, MiddlePoint.Y - 5), new Size(10, 10));

            int WidthAreaNum = (int)Math.Floor((decimal)RoiExtractColorMat.Width / 20) - 4;

            Rectangle[] DownBorderArea = new Rectangle[WidthAreaNum + 1];
            for (int i = 1; i <= WidthAreaNum ; i++)
            {
                DownBorderArea[i] = new Rectangle((i + 2) * 20, RoiExtractColorMat.Height - 30, 10, 10);
            }

            MntColor[] DownAreaResult = new MntColor[WidthAreaNum + 1];

            DownAreaResult[0] = RangeColorRecognize(RoiExtractColorMat, AreaMiddle);
            for (int i = 1; i <= WidthAreaNum ; i++)
            {
                DownAreaResult[i] = RangeColorRecognize(RoiExtractColorMat, DownBorderArea[i]);
            }

            Mat ShowMat = new Mat();
            RoiMat.CopyTo(ShowMat);

            CvInvoke.Rectangle(ShowMat, AreaMiddle, new MCvScalar(255, 0, 0));
            for (int i = 0; i <= WidthAreaNum; i++)
            {
                CvInvoke.Rectangle(ShowMat, DownBorderArea[i], new MCvScalar(255, 0, 0));
            }

            ExtractColorPic.Image = ShowMat;

            return DownAreaResult;
        }
        private MntColor[] TestLeftBorder()
        {
            Mat RoiExtractColorMat = new Mat();
            RoiMat.CopyTo(RoiExtractColorMat);
            Point MiddlePoint = new Point((int)RoiExtractColorMat.Width / 2, (int)RoiExtractColorMat.Height / 2);
            Rectangle AreaMiddle = new Rectangle(new Point(MiddlePoint.X - 5, MiddlePoint.Y - 5), new Size(10, 10));//构造一个以中心点为中心的10*10区域

            int HeightAreaNum = (int)Math.Floor((decimal)RoiExtractColorMat.Height / 20) - 2;//

            Rectangle[] LeftBorderArea = new Rectangle[HeightAreaNum + 1];
            for (int i = 1; i <= HeightAreaNum; i++)
            {
                LeftBorderArea[i] = new Rectangle(20, 20 * i, 10, 10);
            }

            MntColor[] LeftAreaResult = new MntColor[HeightAreaNum + 1];

            LeftAreaResult[0] = RangeColorRecognize(RoiExtractColorMat, AreaMiddle);
            for (int i = 1; i <= HeightAreaNum; i++)
            {
                LeftAreaResult[i] = RangeColorRecognize(RoiExtractColorMat, LeftBorderArea[i]);
            }
            CvInvoke.Rectangle(RoiExtractColorMat, AreaMiddle, new MCvScalar(255, 0, 0));
            for (int i = 0; i <= HeightAreaNum; i++)
            {
                CvInvoke.Rectangle(RoiExtractColorMat, LeftBorderArea[i], new MCvScalar(255, 255, 0));
            }
            ExtractColorPic.Image = RoiExtractColorMat;

            return LeftAreaResult;
        }
        private MntColor[] TestRightBorder()
        {
            Mat RoiExtractColorMat = new Mat();
            RoiMat.CopyTo(RoiExtractColorMat); 
            Point MiddlePoint = new Point((int)RoiExtractColorMat.Width / 2, (int)RoiExtractColorMat.Height / 2);
            Rectangle AreaMiddle = new Rectangle(new Point(MiddlePoint.X - 5, MiddlePoint.Y - 5), new Size(10, 10));

            int HeightAreaNum = (int)Math.Floor((decimal)RoiExtractColorMat.Height / 20) - 2;

            Rectangle[] RightBorderArea = new Rectangle[HeightAreaNum + 1];
            for (int i = 1; i <= HeightAreaNum; i++)
            {
                RightBorderArea[i] = new Rectangle(RoiExtractColorMat.Width - 30, i  * 20, 10, 10);
            }


            MntColor[] RightAreaResult = new MntColor[HeightAreaNum + 1];

            RightAreaResult[0] = RangeColorRecognize(RoiExtractColorMat, AreaMiddle);
            for (int i = 1; i <= HeightAreaNum; i++)
            {
                RightAreaResult[i] = RangeColorRecognize(RoiExtractColorMat, RightBorderArea[i]);
            }

            CvInvoke.Rectangle(RoiExtractColorMat, AreaMiddle, new MCvScalar(255, 0, 0));
            for (int i = 0; i <= HeightAreaNum; i++)
            {
                CvInvoke.Rectangle(RoiExtractColorMat, RightBorderArea[i], new MCvScalar(255, 255, 0));
            }

            ExtractColorPic.Image = RoiExtractColorMat;

            return RightAreaResult;
        }
        private MntColor[] TestBrightLine()
        {
            Mat RoiExtractColorMat = new Mat();
            RoiMat.CopyTo(RoiExtractColorMat);
            Point MiddlePoint = new Point((int)RoiExtractColorMat.Width / 2, (int)RoiExtractColorMat.Height / 2);
            Rectangle AreaMiddle = new Rectangle(new Point(MiddlePoint.X - 5, MiddlePoint.Y - 5), new Size(10, 10));//中心采样区域
            int AreaNum = (int)Math.Floor((decimal)RoiExtractColorMat.Width / 3) - 10;
            Rectangle[] UpBorderArea = new Rectangle[AreaNum];
            for (int i = 1; i < AreaNum; i++)
            {
                //从1开始到Num-1
                UpBorderArea[i] = new Rectangle(3 * (i + 5), (int)RoiExtractColorMat.Height / 2, 1, 1);
            }
            MntColor[] AreaResult = new MntColor[AreaNum];
            AreaResult[0] = RangeColorRecognize(RoiExtractColorMat, AreaMiddle);
            for (int i = 1; i < AreaNum; i++)
            {
                AreaResult[i] = RangeColorRecognize(RoiExtractColorMat, UpBorderArea[i]);
            }
            Mat ShowMat = new Mat();
            RoiMat.CopyTo(ShowMat);
            CvInvoke.Rectangle(ShowMat, AreaMiddle, new MCvScalar(255, 0, 0));
            for (int i = 0; i < AreaNum; i++)
            {
                CvInvoke.Rectangle(ShowMat, UpBorderArea[i], new MCvScalar(255, 0, 0));
            }
            ExtractColorPic.Image = ShowMat;
            return AreaResult;
        }
        private MntColor RangeColorRecognize(Mat mat, Rectangle rect1)
        {
            if (mat.NumberOfChannels == 1)
            {
                Print("请输入三通道图片进行识别", Color.Red);
                return MntColor.Black;
            }
            if(rect1.Width < 1 || rect1.Height != rect1.Width)
            {
                Print("请设置大于1的定位范围进行识别", Color.Red);
                return MntColor.Black;
            }
            Mat mat_HSV = new Mat();
            CvInvoke.CvtColor(mat, mat_HSV, ColorConversion.Bgr2Hsv);
            byte[,,] Matrix = (byte[,,])mat.GetData();//bgr
            byte[,,] Matrix_HSV = (byte[,,])mat_HSV.GetData();//hsv
            int AverageH = 0; int AverageS = 0; int AverageV = 0;
            int AverageR = 0; int AverageG = 0; int AverageB = 0;
            for(int i = rect1.X; i <= rect1.X + rect1.Width - 1; i++)
            {
                for(int j = rect1.Y; j <= rect1.Y + rect1.Height - 1; j++)
                {
                    AverageH += Matrix_HSV[j, i, 0];
                    //Console.WriteLine(Matrix_HSV[j, i, 0]);
                }
            }
            AverageH = (byte)(AverageH / (rect1.Width * rect1.Height));
            for (int i = rect1.X; i <= rect1.X + rect1.Width - 1; i++)
            {
                for (int j = rect1.Y; j <= rect1.Y + rect1.Height - 1; j++)
                {
                    AverageS += Matrix_HSV[j, i, 1];
                    //Console.WriteLine(Matrix_HSV[j, i, 1]);
                }
            }
            AverageS = (byte)(AverageS / (rect1.Width * rect1.Height));
            for (int i = rect1.X; i <= rect1.X + rect1.Width - 1; i++)
            {
                for (int j = rect1.Y; j <= rect1.Y + rect1.Height - 1; j++)
                {
                    AverageV += Matrix_HSV[j, i, 2];
                    //Console.WriteLine(Matrix_HSV[j, i, 2]);
                }
            }
            AverageV = (byte)(AverageV / (rect1.Width * rect1.Height));
            for (int i = rect1.X; i <= rect1.X + rect1.Width - 1; i++)
            {
                for (int j = rect1.Y; j <= rect1.Y + rect1.Height - 1; j++)
                {
                    AverageR += Matrix[j, i, 0];
                }
            }
            AverageR = (byte)(AverageR / (rect1.Width * rect1.Height));
            for (int i = rect1.X; i <= rect1.X + rect1.Width - 1; i++)
            {
                for (int j = rect1.Y; j <= rect1.Y + rect1.Height - 1; j++)
                {
                    AverageG += Matrix[j, i, 0];
                }
            }
            AverageG = (byte)(AverageG / (rect1.Width * rect1.Height));
            for (int i = rect1.X; i <= rect1.X + rect1.Width - 1; i++)
            {
                for (int j = rect1.Y; j <= rect1.Y + rect1.Height - 1; j++)
                {
                    AverageB += Matrix[j, i, 0];
                }
            }
            AverageB = (byte)(AverageB / (rect1.Width * rect1.Height));
            if (AverageS >= 40 && AverageV >= 46)//
            {
                //利用s和v来排除黑白灰
                if ((AverageH >= 0 && AverageH <= 34) || (AverageH >= 156 && AverageH <= 180))
                {
                    //red orange yellow
                    return MntColor.red;
                }
                else if ((AverageH >= 35 && AverageH <= 99))
                {
                    //green
                    return MntColor.green;
                }
                else if ((AverageH >= 100 && AverageH <= 155))
                {
                    //blue purple
                    return MntColor.blue;
                }
            }
            if (AverageR >= 70 && AverageG >= 70 && AverageB >= 70)
            {
                //SetWorkMessage("灰白", Color.Gray);
                return MntColor.GrayWhite;
            }
            else
            {
                //SetWorkMessage("黑色", Color.Gray);
                return MntColor.Black;
            }
        }
        private bool ConsisitencyTest(MntColor[] mntColor)
        {
            if(mntColor.Length != 0)
            {
                MntColor MiddleColor = mntColor[0];
                for (int i = 1;i < mntColor.Length - 2; i++)
                {
                    Console.WriteLine(mntColor[i]);
                    if(mntColor[i] == MntColor.GrayWhite)
                    {
                        continue;
                    }
                    if(mntColor[i] != MiddleColor)
                    {
                        return false;
                    }
                }
                return true;
            }
            else
            {
                return false;
            }
        }
        private void SetWorkStatus(WorkStatus ws)
        {
            if (InvokeRequired)
            {
                Invoke(new Action(() => { SetWorkStatus(ws); }));
            }
            else
            {
                switch (ws)
                {
                    case WorkStatus.Preparing:
                        StatusLabel.Font = new Font("Arial Black", 80);
                        StatusLabel.Text = "准备中";
                        StatusLabel.ForeColor = Color.Black;
                        StatusLabel.BackColor = Color.Yellow;
                        break;
                    case WorkStatus.Ready:
                        StatusLabel.Font = new Font("Arial Black", 80);
                        StatusLabel.Text = "就绪";
                        StatusLabel.ForeColor = Color.White;
                        StatusLabel.BackColor = Color.LightGreen;
                        break;
                    case WorkStatus.Pass:
                        StatusLabel.Font = new Font("Arial Black", 80);
                        StatusLabel.Text = "良品";
                        StatusLabel.ForeColor = Color.White;
                        StatusLabel.BackColor = Color.Green;
                        break;
                    case WorkStatus.NG:
                        StatusLabel.Font = new Font("Arial Black", 80);
                        StatusLabel.Text = "不良品";
                        StatusLabel.ForeColor = Color.White;
                        StatusLabel.BackColor = Color.OrangeRed;
                        break;
                    case WorkStatus.Waiting:
                        StatusLabel.Font = new Font("Arial Black", 80);
                        StatusLabel.Text = "等待中";
                        StatusLabel.ForeColor = Color.DarkCyan;
                        StatusLabel.BackColor = Color.LightGoldenrodYellow;
                        break;
                    case WorkStatus.Offline:
                        StatusLabel.Font = new Font("Arial Black", 80);
                        StatusLabel.Text = "脱机测试";
                        StatusLabel.ForeColor = Color.White;
                        StatusLabel.BackColor = Color.Gray;
                        break;
                }
            }
        }
        public void SetText(string message)
        {
            if (InvokeRequired)
            {
                Invoke(new Action(() => { SetText(message); }));
            }
            else
            {
                this.SnTextBox.Text = message;
            }
        }
        public static Mat MatOpenCVSharpToEmgu(OpenCvSharp.Mat opcvsMat)
        {
            var emguMat = new Mat();
            CvInvoke.Imdecode(opcvsMat.ToBytes(), ImreadModes.AnyColor, emguMat);
            return emguMat;
        }
        private void GrabThread()
        {
            while (m_bGrabLoop)
            {
                if (!m_bStartGrab)
                {
                    Thread.Sleep(10);
                    continue;
                }
                #region 高效取图
                // 主动采集
                // initiative grab 
                if (m_dev != null && m_dev.WaitForFrameTriggerReady(out m_data, 1000))
                {
                    m_grabTime.Stop();
                    //long grabTime = m_grabTime.ElapsedMilliseconds;
                    //string str = "Camera:" + m_dev.DeviceInfo.Key + " BlockID:" + m_data.BlockID + " soft trigger -> frame:" + grabTime + "ms\r\n";
                    //LogHelper.Instance.Write(str, MessageType.Information);
                    m_mutex.WaitOne();
                    try
                    {
                        if (m_bStartGrab)
                        {
                            m_frameList.Add(m_data);
                        }
                    }
                    catch (Exception exception)
                    {
                        Catcher.Show(exception);
                    }
                    m_mutex.ReleaseMutex();
                    #endregion
                }
            }
        }
        private void ShowThread()
        {
            while (m_bShowLoop)
            {
                if (m_frameList.Count == 0)
                {
                    Thread.Sleep(10);
                    continue;
                }

                if (m_frameList.Count > 0) //高效取图时
                {
                    m_mutex.WaitOne();
                    IFrameRawData frame = m_frameList[0];
                    m_frameList.Remove(frame);
                    m_mutex.ReleaseMutex();
                    try
                    {
                        if (CreateOrUpdateMemory(frame) && ImageConvert(frame))
                        {
                            OriginalMat = BitmapExtension.ToMat(m_bitmap);
                            OriginalMat.CopyTo(OriginalMat_Old);//只有Logo测试的ROI采用原图进行裁切
                            CvInvoke.Resize(OriginalMat, OriginalMat, new Size(912, 608));//坐标转换回去刚好是1/6的位置 给画面测试用的
                            pbImage.Image = OriginalMat;
                        }
                    }
                    catch (Exception exception)
                    {
                        Catcher.Show(exception);
                    }
                    finally
                    {
                        if (frame != null)
                        {
                            frame.Dispose();
                        }
                    }
                }
            }
        }
        private bool CreateOrUpdateMemory(IFrameRawData frame)
        {
            if (frame.Width != m_framewidth || frame.Height != m_frameheight)
            {
                if (m_pDstRGB != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(m_pDstRGB);
                }

                //转目标内存
                var ImgSize = RGBFactory.EncodeLen(frame.Width, frame.Height, true);

                //当内存申请失败，进行下一轮运算
                try
                {
                    m_pDstRGB = Marshal.AllocHGlobal(ImgSize);
                }
                catch
                {
                    frame.Dispose();
                    return false;
                }
                if (m_pDstRGB == IntPtr.Zero)
                {
                    frame.Dispose();
                    return false;
                }

                m_framewidth = frame.Width;
                m_frameheight = frame.Height;
            }
            return true;
        }
        private bool ImageConvert(IFrameRawData frame)
        {
            // 转码参数
            m_oParam.width = frame.Width;
            m_oParam.height = frame.Height;
            m_oParam.paddingX = 0;
            m_oParam.paddingY = 0;
            m_oParam.dataSize = frame.RawSize;
            m_oParam.pixelForamt = (uint)frame.PixelFmt;

            int nDesDataSize = 0;
            int ret = IMGCNV_ConvertToBGR24_Ex(frame.RawData, ref m_oParam, m_pDstRGB, ref nDesDataSize, IMGCNV_EBayerDemosaic.IMGCNV_DEMOSAIC_NEAREST_NEIGHBOR);
            if (ret != 0)
            {
                // 转码出错
                frame.Dispose(); //释放驱动缓存
                return false;
            }

            // 更新Bitmap
            CreateOrUpdateBitmap(frame);
            return true;
        }
        private void CreateOrUpdateBitmap(IFrameRawData frame)
        {
            // 用BGR24数据生成Bitmap
            if (m_bitmap == null || m_bitmap.Width != frame.Width || m_bitmap.Height != frame.Height)
            {
                if (m_bitmap != null)
                {
                    m_bitmap.Dispose();
                }
                m_bitmap = new Bitmap(frame.Width, frame.Height, PixelFormat.Format24bppRgb);
            }
            if (m_bitmapRect.Width != m_bitmap.Width || m_bitmapRect.Height != m_bitmap.Height)
            {
                m_bitmapRect.Height = m_bitmap.Height;
                m_bitmapRect.Width = m_bitmap.Width;
            }
            m_bmpData = m_bitmap.LockBits(m_bitmapRect, ImageLockMode.ReadWrite, m_bitmap.PixelFormat);
            CopyMemory(m_bmpData.Scan0, m_pDstRGB, m_bmpData.Stride * m_bitmap.Height);
            m_bitmap.UnlockBits(m_bmpData);
        }
        public Mat FloodFillAreaFind()
        {
            Mat OriginalMat_Hsv = new Mat();
            CvInvoke.CvtColor(OriginalMat, OriginalMat_Hsv, ColorConversion.Bgr2Hsv);
            CvInvoke.Imshow("src", OriginalMat_Hsv);
            Image<Gray, Byte> imgMask = new Image<Gray, Byte>(OriginalMat_Hsv.Width + 2, OriginalMat_Hsv.Height + 2);
            Rectangle rc = new Rectangle(0, 0, 0, 0);
            CvInvoke.FloodFill(OriginalMat_Hsv, imgMask, new Point((int)(OriginalMat_Hsv.Width / 2), (int)(OriginalMat_Hsv.Height / 2)), new MCvScalar(255, 255, 255), out rc, new MCvScalar(9, 9, 9), new MCvScalar(15, 15, 15));
            CvInvoke.Circle(OriginalMat_Hsv, new Point((int)(OriginalMat_Hsv.Width / 2), (int)(OriginalMat_Hsv.Height / 2)), 5, new MCvScalar(255, 255, 255));
            Mat DilateMat = new Mat();
            Mat element = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(15, 15), new Point(-1, -1));
            CvInvoke.Dilate(OriginalMat_Hsv, DilateMat, element, new Point(-1, -1), 1, BorderType.Default, new MCvScalar(128, 128, 128));
            CvInvoke.InRange(DilateMat, new ScalarArray(new MCvScalar(255, 255, 255)), new ScalarArray(new MCvScalar(255, 255, 255)), DilateMat);
            VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
            VectorOfRect hierarchy = new VectorOfRect();
            CvInvoke.FindContours(DilateMat, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxSimple);
            //CvInvoke.DrawContours(OriginalMat, contours, 0, new MCvScalar(0, 255, 0), 1);
            Rectangle rect = CvInvoke.BoundingRectangle(contours[0]);
            return Roi(OriginalMat, rect);
        }
        private void LogoTest()
        {
            if (RoiLogoMat != null && templateMat != null)
            {
                try
                {
                    CvInvoke.CvtColor(RoiLogoMat, observedImage, ColorConversion.Bgr2Gray);
                    CvInvoke.CvtColor(templateMat, modelImage, ColorConversion.Bgr2Gray);
                    Mat result = DrawMatches.Draw(modelImage, observedImage, out matchTime, out matchScore);
                    if (!result.IsEmpty)
                    {
                        LogoPic.Image = result;
                        string msg = $"Match Time: {matchTime}   Match Score: {matchScore}";
                        if (matchScore > 20)
                        {
                            Print($"{msg} 匹配成功", Color.Green);
                        }
                        else
                        {
                            Print($"{msg} 匹配失败", Color.Red);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Print(ex.Message, Color.Red);
                }
            }
        }
        #endregion


    }
    enum MntColor
    {
        red,
        yellow,
        green,
        blue,
        GrayWhite,
        Black
    }
    enum WorkStatus
    {
        Preparing,
        Ready,
        Pass,
        NG,
        Waiting,
        Offline
    };
}
